package com.elitesland.core.exception.rest;

import com.elitesland.core.base.ApiCode;
import com.elitesland.core.base.ApiResult;
import com.elitesland.core.exception.BusinessException;
import com.elitesland.core.vo.RequestBindingErrorVO;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * <pre>
 * [功能说明]
 * </pre>
 *
 * @author Mir
 * @date 2020/6/24
 */
@RestController
@Slf4j
public class FilterErrorController extends BasicErrorController {

    public FilterErrorController() {
        super(new DefaultErrorAttributes(), new ErrorProperties());
    }

    @Override
    @RequestMapping(produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        var body = getErrorAttributes(request, ErrorAttributeOptions.of(
                ErrorAttributeOptions.Include.MESSAGE,
                ErrorAttributeOptions.Include.BINDING_ERRORS,
                ErrorAttributeOptions.Include.STACK_TRACE,
                ErrorAttributeOptions.Include.EXCEPTION));
//        val status = getStatus(request);
        log.error(body.toString());

        val r = ApiResult.fail(ApiCode.FAIL, body.get("message"));
        body = ApiResult.toMap(r);

        val o = request.getAttribute("org.springframework.boot.web.servlet.error.DefaultErrorAttributes.ERROR");
        if (o instanceof BusinessException) {
            val e = (BusinessException) o;
            val result = ApiResult.fail(e.getCode() == null ? ApiCode.FAIL : e.getCode(), e.getMessage());
            body = ApiResult.toMap(result);
        }
        /**
         * 工作流异常
         */
//        if(o instanceof WorkflowException)
//        {
//            val e = (WorkflowException) o;
//            val result = ApiResult.fail( ApiCode.FAIL , e.getMessage());
//            body = ApiResult.toMap(result);
//        }

        if (o instanceof MethodArgumentNotValidException) {
            List<RequestBindingErrorVO> errors = ((MethodArgumentNotValidException) o).getBindingResult().getFieldErrors().stream()
                    .map(e -> {
                        val vo = new RequestBindingErrorVO();
                        vo.setField(e.getField()).setMsg(e.getDefaultMessage());
                        return vo;
                    }).collect(Collectors.toList());
            val result = ApiResult.fail(ApiCode.PARAMETER_EXCEPTION, errors);
            body = ApiResult.toMap(result);
        }

        return ResponseEntity.of(Optional.of(body));
    }

    @Override
    public String getErrorPath() {
        return "error/error";
    }
}
